package com.sika.code.standard.db.algorithm;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.google.common.collect.Lists;
import com.sika.code.common.spring.SpringUtil;
import com.sika.code.standard.db.properties.CustomerShardingProperties;
import com.sika.code.standard.db.properties.ShardingItem;
import org.apache.shardingsphere.api.sharding.complex.ComplexKeysShardingAlgorithm;
import org.apache.shardingsphere.api.sharding.complex.ComplexKeysShardingValue;
import org.apache.shardingsphere.api.sharding.hint.HintShardingAlgorithm;
import org.apache.shardingsphere.api.sharding.hint.HintShardingValue;
import org.apache.shardingsphere.api.sharding.standard.PreciseShardingAlgorithm;
import org.apache.shardingsphere.api.sharding.standard.PreciseShardingValue;

import java.util.Collection;

/**
 * 基础分片算法
 */
public interface BaseShardingAlgorithm<T extends Comparable<?>> extends PreciseShardingAlgorithm<T>, HintShardingAlgorithm<T>, ComplexKeysShardingAlgorithm<T> {

    /**
     * 从上下文钟获取数据库名称|表名
     */
    default String getNameFromContext(String expression, Collection<Comparable<?>> shardValues) {
        if (CollUtil.isNotEmpty(shardValues)) {
            Object [] comparators = shardValues.toArray();
            return formatExpression(expression, comparators);
        }
        return null;
    }

    /**
     * 格式化表达式
     */
    default String formatExpression(String expression, Object... params) {
        return StrUtil.format(expression, params);
    }

    default ShardingItem getShardingItem(String logicTableName) {
        return SpringUtil.getBean(CustomerShardingProperties.class).getShardingItemMap().get(logicTableName);
    }


    default ShardingValueContext<T> buildShardingValueContext(Collection<String> availableTargetNames, PreciseShardingValue<T> shardingValue) {
        return new ShardingValueContext<T>().setValues(Lists.newArrayList(shardingValue.getValue()))
                .setColumnName(shardingValue.getColumnName())
                .setLogicTableName(shardingValue.getLogicTableName())
                .setAvailableTargetNames(availableTargetNames);
    }

    default ShardingValueContext<T> buildShardingValueContext(Collection<String> availableTargetNames, HintShardingValue<T> shardingValue) {
        return new ShardingValueContext<T>().setValues(shardingValue.getValues())
                .setColumnName(shardingValue.getColumnName())
                .setLogicTableName(shardingValue.getLogicTableName())
                .setAvailableTargetNames(availableTargetNames);
    }

    default ShardingValueContext<T> buildShardingValueContext(Collection<String> availableTargetNames, ComplexKeysShardingValue<T> shardingValue) {
        return new ShardingValueContext<T>().setValues(shardingValue.getColumnNameAndShardingValuesMap().values().iterator().next())
                .setColumnName(shardingValue.getColumnNameAndShardingValuesMap().keySet().iterator().next())
                .setLogicTableName(shardingValue.getLogicTableName())
                .setAvailableTargetNames(availableTargetNames);
    }

}
